/*
	Visp is an opensource visual performance application built with Adobe® AIR™.
	
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
	
	Mike Creighton can be found at http://www.mikecreighton.com	
*/
package com.visp.render
{
	import com.visp.constants.*;
	
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import mx.collections.ArrayCollection;
	import com.visp.transitions.TransitionManager;
	import com.visp.events.TransitionEvent;
	import com.visp.transitions.ITransition;
	import com.visp.input.InputManager;
	import com.visp.events.BangEvent;
	import com.visp.events.RangeEvent;
	import com.visp.filters.FilterManager;
	import com.visp.filters.IFilter;
	import com.visp.events.DisplayMouseEvent;
	import com.visp.events.RendererEvent;
	import com.visp.events.ColorEvent;

	[Event(name="newColor", type="com.visp.events.ColorEvent")]

	public class RenderManager extends EventDispatcher 
	{
		
		public static var outputBitmapData : BitmapData;
		
		private static var _RECT : Rectangle = new Rectangle(0, 0, OutputSize.WIDTH, OutputSize.HEIGHT);
		private static var _DEFAULT_BG_COLOR : uint = 0xFF000000;
		
		private var _queuedLayer : Layer;
		private var _activeLayer : Layer;
		private var _bgColor : uint;
		
		public function RenderManager(target:IEventDispatcher=null)
		{
			super(target);
			
			RenderManager.outputBitmapData = new BitmapData(OutputSize.WIDTH, OutputSize.HEIGHT, true, _DEFAULT_BG_COLOR);
			_bgColor = _DEFAULT_BG_COLOR;
			
			_queuedLayer = new Layer();
			_activeLayer = new Layer();
		}
		
		public function queueLayer(e : RendererEvent) : void
		{
			var r : IRenderable = e.getRenderer();
			// Need to get it subscribed right away to the input manager.
			InputManager.getInstance().addEventListener(BangEvent.BANG_ON, r.handleBangOn);
			InputManager.getInstance().addEventListener(BangEvent.BANG_OFF, r.handleBangOff);
			InputManager.getInstance().addEventListener(RangeEvent.RANGE, r.handleRange);
			InputManager.getInstance().addEventListener(DisplayMouseEvent.DOWN, r.handleMouseEvent);
			InputManager.getInstance().addEventListener(DisplayMouseEvent.DOWN_MOVE, r.handleMouseEvent);
			InputManager.getInstance().addEventListener(DisplayMouseEvent.UP, r.handleMouseEvent);
			InputManager.getInstance().addEventListener(DisplayMouseEvent.MOUSE_CLICK, r.handleMouseEvent);
			
			if(!_queuedLayer.isEmpty()){
				var q : IRenderable = _queuedLayer.getRenderer();
				InputManager.getInstance().removeEventListener(BangEvent.BANG_ON, q.handleBangOn);
				InputManager.getInstance().removeEventListener(BangEvent.BANG_OFF, q.handleBangOff);
				InputManager.getInstance().removeEventListener(RangeEvent.RANGE, q.handleRange);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.DOWN, q.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.DOWN_MOVE, q.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.UP, q.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.MOUSE_CLICK, q.handleMouseEvent);
				_queuedLayer.removeRenderer();
				_queuedLayer.nullifyRenderer();
			}
			
			_queuedLayer.setRenderer(r);
			_queuedLayer.getRenderer().start();
			
			// See if we want to promote this queued layer when
			//   a) we've got not transition
			//   b) we've got no active layer
			if(!TransitionManager.getInstance().hasTransition || _activeLayer.isEmpty()) {
				_promoteQueuedLayer();
			} else {
				TransitionManager.getInstance().getTransition().start(_queuedLayer.outputBitmap, _activeLayer.outputBitmap);
			}
		}
		
		public function handleRemovedTransition(e : TransitionEvent) : void {
			// A person may have removed this during the transition phase, so do a layer
			// swap if a queued layer exists.
			if(!_queuedLayer.isEmpty())
				_promoteQueuedLayer();
		}
		
		public function handleExpiredTransition(e : TransitionEvent) : void {
			// We need to do a layer swap
			_promoteQueuedLayer();
		}
		
		private function _promoteQueuedLayer() : void {
			if(!_activeLayer.isEmpty()){
				var r : IRenderable = _activeLayer.getRenderer();
				InputManager.getInstance().removeEventListener(BangEvent.BANG_ON, r.handleBangOn);
				InputManager.getInstance().removeEventListener(BangEvent.BANG_OFF, r.handleBangOff);
				InputManager.getInstance().removeEventListener(RangeEvent.RANGE, r.handleRange);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.DOWN, r.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.DOWN_MOVE, r.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.UP, r.handleMouseEvent);
				InputManager.getInstance().removeEventListener(DisplayMouseEvent.MOUSE_CLICK, r.handleMouseEvent);
			}
			_activeLayer.removeRenderer();
			_activeLayer.setRenderer(_queuedLayer.getRenderer());
			_queuedLayer.nullifyRenderer();
		}
		
		public function getBackgroundColor() : uint
		{
			return _bgColor;
		}
		
		/**
		 * Updates the output BitmapData instance with the current state
		 * of all renderers in the render queue.
		 */
		public function render(e : Event) : void 
		{
			RenderManager.outputBitmapData.lock();
			
			// Clear our output
			RenderManager.outputBitmapData.fillRect(RenderManager._RECT, _bgColor);
			
			if(!_queuedLayer.isEmpty()) {
				_queuedLayer.render();
			}
			
			if(!_activeLayer.isEmpty()) {
				_activeLayer.render();
			}
			
			// If we're transitioning, then we want to render the output from the transition
			if(TransitionManager.getInstance().hasTransition && !_queuedLayer.isEmpty()){
				var transition : ITransition = TransitionManager.getInstance().getTransition();
				var transitionBitmapData : BitmapData = transition.render(_queuedLayer.outputBitmap, _activeLayer.outputBitmap);
				RenderManager.outputBitmapData.draw(transitionBitmapData);
				
			//	Otherwise, we just want to snag whatever's in the active layer
			} else if(!_activeLayer.isEmpty()) {
				RenderManager.outputBitmapData.draw(_activeLayer.outputBitmap);
				
			}
			
			// Run the filters on the output image
			var fm : FilterManager = FilterManager.getInstance();
			var filterLayers : Array = fm.getFilters();
			if(filterLayers.length > 0){
				var i : int = -1;
				var filter : IFilter;
				while(++i < filterLayers.length){
					filter = filterLayers[i];
					filter.apply(RenderManager.outputBitmapData);
				}
			}
			
			// Good to go, unlock the bitmap
			RenderManager.outputBitmapData.unlock();
		}
	}
}